package com.example.socket.handler;

import com.example.socket.core.Request;
import com.example.socket.core.Session;
import com.example.socket.exception.ErrorForwardException;
import com.example.socket.exception.ProcessingException;
import com.example.socket.parameter.ResultCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author frank
 * 注释方法的{@link Processor}
 */
public class MethodProcessor implements Processor {

    private static final Logger logger = LoggerFactory.getLogger(MethodProcessor.class);

    /**
     * 创建 {@link MethodProcessor}实例
     * @param format 编码格式
     * @param target 方法所在对象
     * @param method 代理方法
     * @return
     */
    public static MethodProcessor valueOf(byte format, Object target, Method method, ParameterBuilder builder) {
        MethodProcessor result = new MethodProcessor();
        ReflectionUtils.makeAccessible(method);
        MethodDefinition definition = MethodDefinition.valueOf(format, target.getClass(), method, builder);

        result.target = target;
        result.method = method;
        result.definition = definition;
        return result;
    }

    /**
     * 创建 {@link MethodProcessor}实例
     * @param format 编码格式
     * @param clz 方法所在的类
     * @param target 方法所在对象
     * @param method 代理方法
     * @return
     */
    public static MethodProcessor valueOf(byte format, Class<?> clz, Object target, Method method,
                                          ParameterBuilder builder) {
        MethodProcessor result = new MethodProcessor();
        ReflectionUtils.makeAccessible(method);
        MethodDefinition definition = MethodDefinition.valueOf(format, clz, method, builder);

        result.target = target;
        result.method = method;
        result.definition = definition;
        return result;
    }

    private Object target;
    private Method method;
    private MethodDefinition definition;

    @Override
    public void process(Request request, Session session, ResultCallback callback) {
        try {
            // 设置当前线程SESSION
            Session.THREAD_LOCAL.set(session);
            Object[] args = definition.buildParameters(request, session, callback);
            Object result = method.invoke(target, args);
            if (definition.noreply) {
                return;
            }
            if (!definition.isCallback() && callback != null) {
                callback.call(result);
            }
        } catch (ProcessingException e) {
            throw e;
        } catch (ErrorForwardException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("模块异常: ", e);
            }
            throw e;
        } catch (Exception e) {
            // 如果是模块异常 返回错误码
            if (e instanceof InvocationTargetException) {
                InvocationTargetException invocationTargetException = (InvocationTargetException) e;
                Throwable targetException = invocationTargetException.getTargetException();
                if (targetException instanceof ErrorForwardException) {
                    ErrorForwardException managedException = (ErrorForwardException) targetException;
                    throw managedException;
                }
            }
            FormattingTuple message = MessageFormatter.format("对象[{}]的方法[{}]访问异常", target.getClass().getName(),
                    method.getName());
            logger.error(message.getMessage(), e);
            throw new ProcessingException(message.getMessage(), e);
        } finally {
            // 清除当前线程SESSION
            Session.THREAD_LOCAL.remove();
        }
    }

    public TypeDefinition getDefinition() {
        return definition;
    }

    public Object getTarget() {
        return target;
    }

    @Override
    public String toString() {
        return target.getClass().getName() + "." + method.getName();
    }

}
